package cn.lingyangwl.agile.auth.controller;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import cn.lingyangwl.framework.core.response.Resp;
import cn.lingyangwl.framework.core.utils.servlet.ServletUtils;
import cn.lingyangwl.framework.tool.core.Base64Utils;
import cn.lingyangwl.framework.tool.core.StringUtils;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;

/**
 * 代理服务, 主要对高德地图等第三方接口进行代理, 降低安全问题(可以做一些校验)
 * @author shenguangyang
 */
@Slf4j
@Api(tags = "代理")
@RestController
@RequestMapping("/proxy/lua")
@RequiredArgsConstructor
public class ProxyController {
    @Resource
    private HttpClient httpClient;

    /**
     * nginx lua脚本中会请求
     */
    @PostMapping("/demo01")
    public void demo01(HttpServletRequest request, HttpServletResponse response) throws Exception {
        byte[] bytes = IoUtil.readBytes(request.getInputStream());
        log.info(new String(bytes, StandardCharsets.UTF_8));
        response.setCharacterEncoding("UTF-8");
        StreamUtils.copy(Base64.getEncoder().encode("123456".getBytes()), response.getOutputStream());
    }

    @PostMapping("/demo02")
    public Resp<?> demo02(HttpServletRequest request) throws Exception {
        byte[] bytes = IoUtil.readBytes(request.getInputStream());
        try {
            log.info(new String(Base64Utils.decode(new String(bytes))));
        } catch (Exception e) {
            log.info(new String(bytes, StandardCharsets.UTF_8));
        }
        return Resp.ok();
    }

    @RequestMapping(value = "/amap/**", method = {
            RequestMethod.DELETE, RequestMethod.OPTIONS, RequestMethod.POST, RequestMethod.GET,
            RequestMethod.PUT
    })
    public void proxyAmap(@RequestParam Map<String, Object> urlParams,
                          HttpServletRequest request, HttpServletResponse response) throws Exception {
        urlParams.put("jscode", "123");
        String requestUri = request.getRequestURI().replace("/proxy/amap", "");
        String baseUrl = "https://restapi.amap.com"; // Web服务API 代理
        if ("/_AMapService/v4/map/styles".equals(requestUri)) { // 自定义地图服务代理
            baseUrl = "https://webapi.amap.com/v4/map/styles";
        } else if ("/_AMapService/v3/vectormap".equals(requestUri)) { // 海外地图服务代理
            baseUrl = "https://fmap01.amap.com/v3/vectormap";
        }
        String url = UrlBuilder.of(baseUrl  + requestUri).setQuery(UrlQuery.of(urlParams)).build();
        doProxy(url, request, response);
    }


    private void doProxy(String url, HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.reset();
        String method = request.getMethod();
        String bodyString = ServletUtils.getBodyString(request);
        Method httpMethod = Arrays.stream(Method.values()).filter(e -> e.name().equalsIgnoreCase(method))
                .findFirst().orElseThrow(() -> new BizException("请求方法不被支持"));
        HttpRequest httpRequest = HttpUtil.createRequest(httpMethod, url);
        if (StringUtils.isNotEmpty(bodyString)) {
            httpRequest.body(bodyString);
        }
        StringEntity requestEntity = new StringEntity(bodyString, request.getContentType());
        HttpUriRequest httpUriRequest;
        if (httpMethod == Method.DELETE) {
            httpUriRequest = new HttpDelete(url);
        } else if (httpMethod == Method.POST) {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(requestEntity);
            httpUriRequest = httpPost;
        } else if (httpMethod == Method.GET) {
            httpUriRequest = new HttpGet(url);
        } else if (httpMethod == Method.OPTIONS) {
            return;
        } else {
            throw new BizException("不支持的请求方法");
        }
        ServletUtils.getHeaders().forEach(httpUriRequest::addHeader);

        httpUriRequest.addHeader("host", URLUtil.getHost(new URL(url)).getHost());
        ServletOutputStream outputStream = response.getOutputStream();
        HttpResponse httpResponse = httpClient.execute(httpUriRequest);
        try {
            response.setStatus(httpResponse.getStatusLine().getStatusCode());
            Header contentType = httpResponse.getEntity().getContentType();
            response.addHeader(contentType.getName(), contentType.getValue());
            // 拷贝头部
//            Arrays.stream(httpResponse.getAllHeaders()).forEach((header) -> response.addHeader(header.getName(), header.getValue()));
            InputStream inputStream = httpResponse.getEntity().getContent();
            byte[] b = new byte[4096];
            int len;
            // 从输入流中读取一定数量的字节，并将其存储在缓冲区字节数组中，读到末尾返回-1
            while ((len = inputStream.read(b)) > 0) {
                outputStream.write(b, 0, len);
            }
            outputStream.flush();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

}
